package com.context;

import com.annotation.Autowired;
import com.annotation.Bean;
import com.annotation.Component;
import com.annotation.Configuration;
import com.config.AppConfig;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AnnotationConfigApplicationContext {
    private final Map<String, Object> beanMap = new ConcurrentHashMap<>();
    private final Map<String, Class<?>> beanDefinitionMap = new ConcurrentHashMap<>();

    public AnnotationConfigApplicationContext(Class<?> configClass) {
        try {
            System.out.println("开始初始化IOC容器...");

            // 处理配置类
            processConfigClass(configClass);

            // 扫描多个包：配置类所在的包和相关的服务包
            String basePackage = configClass.getPackage().getName();
            scanComponents(basePackage); // 扫描配置类所在的包

            // 同时扫描service包
            String servicePackage = "com.service";
            if (!servicePackage.equals(basePackage)) {
                scanComponents(servicePackage);
            }

            // 执行依赖注入
            performDependencyInjection();

            System.out.println("IOC容器初始化完成，共注册Bean: " + beanMap.size());
        } catch (Exception e) {
            throw new RuntimeException("IOC容器初始化失败", e);
        }
    }

    private void processConfigClass(Class<?> configClass) {
        if (!configClass.isAnnotationPresent(Configuration.class)) {
            throw new RuntimeException("提供的类不是配置类: " + configClass.getName());
        }

        System.out.println("处理配置类: " + configClass.getName());

        try {
            Object configInstance = configClass.getDeclaredConstructor().newInstance();

            for (Method method : configClass.getDeclaredMethods()) {
                if (method.isAnnotationPresent(Bean.class)) {
                    String beanName = method.getAnnotation(Bean.class).value();
                    if (beanName.isEmpty()) {
                        beanName = method.getName();
                    }

                    System.out.println("创建Bean: " + beanName);
                    Object bean = method.invoke(configInstance);
                    beanMap.put(beanName, bean);
                    beanDefinitionMap.put(beanName, bean.getClass());
                    System.out.println("Bean创建成功: " + beanName + " -> " + bean.getClass().getName());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("处理配置类失败: " + configClass.getName(), e);
        }
    }

    private void scanComponents(String basePackage) {
        System.out.println("扫描包: " + basePackage);

        try {
            String path = basePackage.replace('.', '/');
            URL resource = Thread.currentThread().getContextClassLoader().getResource(path);

            if (resource == null) {
                System.out.println("未找到包路径: " + path);
                return;
            }

            File directory = new File(resource.getFile());
            if (!directory.exists()) {
                System.out.println("目录不存在: " + directory.getAbsolutePath());
                return;
            }

            scanDirectory(directory, basePackage);
        } catch (Exception e) {
            throw new RuntimeException("扫描组件失败", e);
        }
    }

    private void scanDirectory(File directory, String packageName) {
        File[] files = directory.listFiles();
        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                scanDirectory(file, packageName + "." + file.getName());
            } else if (file.getName().endsWith(".class")) {
                String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
                processClass(className);
            }
        }
    }

    private void processClass(String className) {
        try {
            Class<?> clazz = Class.forName(className);

            if (clazz.isAnnotationPresent(Component.class)) {
                String beanName = clazz.getSimpleName();
                beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);

                System.out.println("发现组件: " + beanName);

                // 创建Bean实例
                Object bean = clazz.getDeclaredConstructor().newInstance();
                beanMap.put(beanName, bean);
                beanDefinitionMap.put(beanName, clazz);
                System.out.println("Bean创建成功: " + beanName + " -> " + clazz.getName());
            }
        } catch (ClassNotFoundException e) {
            System.out.println("类未找到: " + className);
        } catch (Exception e) {
            System.out.println("处理类失败: " + className + ", 错误: " + e.getMessage());
        }
    }

    private void performDependencyInjection() {
        System.out.println("开始依赖注入...");

        for (Object bean : beanMap.values()) {
            Class<?> clazz = bean.getClass();

            // 字段注入
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    String fieldName = field.getName();
                    Object dependency = getBean(fieldName);

                    if (dependency != null) {
                        try {
                            field.setAccessible(true);
                            field.set(bean, dependency);
                            System.out.println("注入字段: " + fieldName + " -> " + bean.getClass().getSimpleName());
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException("字段注入失败: " + fieldName, e);
                        }
                    } else {
                        System.out.println("警告: 未找到依赖Bean: " + fieldName);
                    }
                }
            }
        }
    }

    public <T> T getBean(Class<T> clazz) {
        for (Object bean : beanMap.values()) {
            if (clazz.isInstance(bean)) {
                return clazz.cast(bean);
            }
        }
        return null;
    }

    public Object getBean(String beanName) {
        return beanMap.get(beanName);
    }

    public int getBeanCount() {
        return beanMap.size();
    }

    public List<String> getBeanNames() {
        return new ArrayList<>(beanMap.keySet());
    }

    public void destroy() {
        System.out.println("销毁IOC容器...");
        beanMap.clear();
        beanDefinitionMap.clear();
    }
}